
logo = """
 _____  _    ____   _____             _                     ___   ____   ___  
|_   _|/ \  / ___| | ____|_ __   __ _(_)_ __   ___  __   __/ _ \ |___ \ / _ \ 
  | | / _ \| |  _  |  _| | '_ \ / _` | | '_ \ / _ \ \ \ / / | | |  __) | | | |
  | |/ ___ \ |_| | | |___| | | | (_| | | | | |  __/  \ V /| |_| | / __/| |_| |
  |_/_/   \_\____| |_____|_| |_|\__, |_|_| |_|\___|   \_/  \___(_)_____|\___/ 
                                |___/                                         
"""
__author__ = "Shuhao Wu"
__copyright__ = "Copyright 2010, Shuhao Wu, TAG Engine development team"
__license__ = "Apache License 2.0"
__version__ = "trunk"
__email__ = "admin@thekks.net"
__status__ = "Development"

import sys
import os
import logging
import random
from tagengine import constants
from tagengine.commons import *
from tagengine.objects import BaseObject
from tagengine.parsers import xmlparser, languageparser
from tagengine import core

# Allow outer access with tagengine.System
System = core.System

DEBUG_LEVEL = logging.DEBUG
ROOT_DIR = os.path.dirname(os.path.realpath(__file__))

logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=DEBUG_LEVEL)
logger = logging.getLogger("tagengine")

class Game(BaseObject, core.Plugin):
    VERSION = 0.2
    """ Game class. """
    class AllTriggers(object):
        """ This class will import all methods and classes in a module and
            append it as it's own function.
            modules are list of import <names>.
        """
        def __init__(self, *modules):
            self += modules
        def __iadd__(self, modules):
            for module in modules:
                exec "from %s import *" % module in self.__dict__
            return self
        
    def __init__(self, xmlfiles, customtriggers=None, customxmlformats=[], customimports=[]):
        global triggers
        self.xmlfiles = xmlfiles
        self.xmlformats = customxmlformats
        
        self.name = "TAG Engine Game Class"
        self.uniquename = "tag-game"
        self.critical = True
        
        self.game = self
        
        self.varname = "game"
        
        self.running = False
        self.firstRun = True
        
        # Trigger importing.
        try:
            if not customtriggers:
                raise ImportError
            self.triggers = self.AllTriggers("tagengine.triggers", customtriggers)
        except ImportError:
            if customtriggers:
                raise TriggerNotFoundError("Custom triggers are specified while no file is found!")
            logger.warning("No custom triggers are found. Using the default ones.")
            self.triggers = self.AllTriggers("tagengine.triggers")
        
        self.extras = core.PluggableImports(customimports, [os.path.join(ROOT_DIR, "objects"), os.path.join(ROOT_DIR, "commons")])
        
        self.output = self.extras.get("commons.output")
        self.getInput = self.extras.get("commons.getInput")
        
        self.init()

    def init(self):
        pass
        
    def load(self, system):
        self.system = system
        self.running = True
        return True
    
    def unload(self, system):
        return False
    
    def prepare(self, system):
        system.events.registerPluginToEvent(self, "SystemInit", "generateWorld")
        # Register some events in the system.
        for event in ("BeforeWorldGeneration", 
                      "BeforeMainLoop", 
                      "TriggerFired", 
                      "PlayerMoved", 
                      "PlayerAction",
                      "ValidCommandParsed",
                      "GameEventFired", # Not the be confused with the system Events
                      "GameWon", 
                      "GameLost"):
            
            system.events.registerEvent(event)
    
    def generateWorld(self, args=None):
        self.system.events.fire("BeforeWorldGeneration", True, game=self, signaller=self)
        
        parsed = xmlparser.TAGxMLParser(self.xmlfiles, self.xmlformats)
        
        self.objects = {}
        self.aliasTable = {}
        
        self.data = parsed.data.pop("game")["game"] # Extract data.
        
        for name in parsed.data:
            #if name == "game":
            #    continue
            classname = parsed.format[name]["classname"]
            cls = self.extras.get(classname)
            self.objects[name] = {}
            for varname in parsed.data[name]:
                self.objects[name][varname] = cls(parsed.data[name][varname], varname, self)
                setattr(self, varname, self.objects[name][varname])
                
        for name in self.objects:           
            for varname in self.objects[name]:
                self.objects[name][varname].connect()
                
        self.connect()
        return True
    
    def mainloop(self):
        self.system.events.fire("BeforeMainLoop", True, game=self, signaller=self)
        
        if self.firstRun:
            self.firstRun = False
            logger.info("TAG Engine %.3f game started." % self.VERSION)
            
            self.output(self.startmsg)
            
            if self.displayfirstroom:
                self.output(self.player.location.generateDescription())
        
        loop = self.extras.get("commons.mainLoop")
        logger.debug("MainLoop Function: %s" % str(loop))
        won = loop(self)
        
        self.endGame(won)
    
    def update(self):
        pass
    
    def performCommand(self, cmd):
        pass
    
    def endGame(self, won=True, askRestart=True):
        if won == None:
            return None
        
        if won:
            self.system.events.fire("GameWon", True, game=self, signaller=self)
            self.output(self.winmsg)
        else:
            self.system.events.fire("GameLost", True, game=self, signaller=self)
            self.output(self.losemsg)
            
        if askRestart:
            if self.getInput("Would you like to restart? [Y/N] ") == "y":
                self.restartGame()
                return
        
        self.running = False
        
        logger.info("<TAG> Engine will now exit.")
        sys.exit(0)
        
    
        